package com.example.musicaiap.data.repository

import android.util.Log
import com.example.musicaiap.data.database.CurrentPlaylistEntity
import com.example.musicaiap.data.database.MusicDatabase
import com.example.musicaiap.data.database.PlaylistEntity
import com.example.musicaiap.data.database.PlaylistSongCrossRef
import com.example.musicaiap.data.database.SongEntity
import com.example.musicaiap.data.database.PlayHistoryEntity
import com.example.musicaiap.domain.model.Playlist
import com.example.musicaiap.domain.model.Song
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Singleton

/**
 * 音乐仓库Room数据库实现
 * 使用Room数据库持久化存储音乐数据
 */
@Singleton
class RoomMusicRepository @Inject constructor(
    private val database: MusicDatabase,
    // 使用FakeMusicRepository用于初始提供在线内容，实际项目应替换为真实的网络API
    private val fakeMusicRepository: FakeMusicRepository
) : MusicRepository {
    
    private val TAG = "RoomMusicRepository"
    
    private val songDao = database.songDao()
    private val playlistDao = database.playlistDao()
    private val playlistSongDao = database.playlistSongDao() 
    val currentPlaylistDao = database.currentPlaylistDao()
    private val playHistoryDao = database.playHistoryDao()
    
    override suspend fun getRecommendSongs(): List<Song> {
        // 仍使用假数据仓库获取推荐歌曲，但这些歌曲会被缓存到数据库中
        val recommendSongs = fakeMusicRepository.getRecommendSongs()
        
        // 将推荐歌曲存储到数据库
        val songEntities = recommendSongs.map { SongEntity.fromDomainModel(it) }
        songDao.insertSongs(songEntities)
        
        return recommendSongs
    }
    
    override suspend fun getPlaylists(): List<Playlist> {
        // 先尝试从数据库获取播放列表
        val playlistEntities = playlistDao.getAllPlaylists()
        
        // 如果数据库中没有播放列表，则从假数据获取并保存到数据库
        if (playlistEntities.isEmpty()) {
            val fakePlaylists = fakeMusicRepository.getPlaylists()
            val entities = fakePlaylists.map { PlaylistEntity.fromDomainModel(it, false) }
            playlistDao.insertPlaylists(entities)
            
            // 同时保存播放列表中的歌曲关系
            for (playlist in fakePlaylists) {
                val songs = fakeMusicRepository.getPlaylistSongs(playlist.id)
                if (songs.isNotEmpty()) {
                    // 保存歌曲
                    val songEntities = songs.map { SongEntity.fromDomainModel(it) }
                    songDao.insertSongs(songEntities)
                    
                    // 保存关系
                    val crossRefs = songs.mapIndexed { index, song ->
                        PlaylistSongCrossRef(
                            playlistId = playlist.id,
                            songId = song.id,
                            position = index
                        )
                    }
                    playlistSongDao.addSongsToPlaylist(crossRefs)
                }
            }
            
            return fakePlaylists
        }
        
        // 为每个播放列表获取歌曲数量
        return playlistEntities.map { entity ->
            val songCount = playlistSongDao.countSongsInPlaylist(entity.id)
            entity.toDomainModel(songCount)
        }
    }
    
    override suspend fun getPlaylist(playlistId: String): Playlist {
        // 先尝试从数据库获取
        val playlistEntity = playlistDao.getPlaylistById(playlistId)
            ?: // 如果数据库中没有，则从假数据获取并保存
            let {
                val fakePlaylist = fakeMusicRepository.getPlaylist(playlistId)
                val entity = PlaylistEntity.fromDomainModel(fakePlaylist)
                playlistDao.insertPlaylist(entity)
                entity
            }
        
        val songCount = playlistSongDao.countSongsInPlaylist(playlistId)
        return playlistEntity.toDomainModel(songCount)
    }
    
    override suspend fun getPlaylistSongs(playlistId: String): List<Song> {
        // 获取播放列表中的所有歌曲ID
        val songIds = playlistSongDao.getSongIdsInPlaylist(playlistId)
        
        // 如果数据库中有这些歌曲，直接返回
        if (songIds.isNotEmpty()) {
            val songsFromDb = songDao.getSongsByIds(songIds)
            if (songsFromDb.size == songIds.size) {
                // 数据库中已有所有歌曲，按照播放列表中的顺序返回
                val orderedSongs = songIds.mapNotNull { id ->
                    songsFromDb.find { it.id == id }?.toDomainModel()
                }
                return orderedSongs
            }
        }
        
        // 如果数据库中没有或不完整，从假数据获取并保存
        val fakeSongs = fakeMusicRepository.getPlaylistSongs(playlistId)
        if (fakeSongs.isNotEmpty()) {
            // 保存歌曲
            val songEntities = fakeSongs.map { SongEntity.fromDomainModel(it) }
            songDao.insertSongs(songEntities)
            
            // 保存关系
            playlistSongDao.clearPlaylist(playlistId) // 清空旧关系
            val crossRefs = fakeSongs.mapIndexed { index, song ->
                PlaylistSongCrossRef(
                    playlistId = playlistId,
                    songId = song.id,
                    position = index
                )
            }
            playlistSongDao.addSongsToPlaylist(crossRefs)
        }
        
        return fakeSongs
    }
    
    override suspend fun getSong(songId: String): Song {
        // 先从数据库获取
        val songEntity = songDao.getSongById(songId)
        
        // 如果数据库中有，直接返回
        if (songEntity != null) {
            return songEntity.toDomainModel()
        }
        
        // 否则从假数据获取并保存到数据库
        val fakeSong = fakeMusicRepository.getSong(songId)
        songDao.insertSong(SongEntity.fromDomainModel(fakeSong))
        return fakeSong
    }
    
    override fun getSongById(songId: String): Song? {
        Log.d(TAG, "查询歌曲ID: $songId")
        
        // 从数据库同步获取，无法使用挂起函数
        val songEntity = songDao.getSongByIdSync(songId)
        
        if (songEntity != null) {
            Log.d(TAG, "在数据库中找到: ${songEntity.title}")
            return songEntity.toDomainModel()
        }
        
        // 如果数据库中没有，尝试从假数据获取
        val song = fakeMusicRepository.getSongById(songId)
        if (song != null) {
            Log.d(TAG, "在假数据中找到: ${song.title}")
            // 注意：这里不能同步保存到数据库，因为Room不允许在主线程执行数据库操作
        }
        
        return song
    }
    
    override fun getSongsByPlaylistId(playlistId: String): List<Song> {
        // 获取播放列表中的所有歌曲ID
        val songIds = playlistSongDao.getSongIdsInPlaylistSync(playlistId)
        
        // 如果没有歌曲ID，使用假数据
        if (songIds.isEmpty()) {
            return fakeMusicRepository.getSongsByPlaylistId(playlistId)
        }
        
        // 从数据库获取歌曲
        val songs = songIds.mapNotNull { songId ->
            songDao.getSongByIdSync(songId)?.toDomainModel()
        }
        
        // 如果数据库中的歌曲数不足，则使用假数据
        return if (songs.size == songIds.size) {
            songs
        } else {
            fakeMusicRepository.getSongsByPlaylistId(playlistId)
        }
    }
    
    override suspend fun searchSongs(query: String): List<Song> {
        // 简单实现，直接使用假数据仓库的搜索功能
        return fakeMusicRepository.searchSongs(query)
    }
    
    override suspend fun getLyrics(songId: String): String? {
        // 简单实现，直接使用假数据仓库获取歌词
        return fakeMusicRepository.getLyrics(songId)
    }
    
    override suspend fun addToFavorites(songId: String) {
        Log.d(TAG, "添加歌曲到收藏: $songId")
        
        // 获取或创建收藏播放列表
        var favoritePlaylist = playlistDao.getFavoritePlaylist()
        if (favoritePlaylist == null) {
            favoritePlaylist = PlaylistEntity.createFavoritePlaylist()
            playlistDao.insertPlaylist(favoritePlaylist)
            Log.d(TAG, "创建收藏播放列表: ${favoritePlaylist.id}")
        } else {
            Log.d(TAG, "已存在收藏播放列表: ${favoritePlaylist.id}")
        }
        
        // 确保歌曲存在于数据库
        val song = songDao.getSongByIdSync(songId)
        if (song == null) {
            // 如果歌曲不存在于数据库，从假数据仓库获取并保存
            Log.d(TAG, "歌曲 $songId 不存在于数据库，尝试从假数据获取")
            fakeMusicRepository.getSongById(songId)?.let {
                val songEntity = SongEntity.fromDomainModel(it)
                songDao.insertSong(songEntity)
                Log.d(TAG, "保存歌曲到数据库: $songId, 标题: ${it.title}")
            } ?: Log.e(TAG, "无法找到歌曲: $songId")
        } else {
            Log.d(TAG, "歌曲已存在于数据库: $songId, 标题: ${song.title}")
        }
        
        // 检查歌曲是否已在收藏列表中
        val isAlreadyFavorite = playlistSongDao.isSongInPlaylist(favoritePlaylist.id, songId)
        if (!isAlreadyFavorite) {
            // 获取收藏列表中的最大位置
            val maxPosition = playlistSongDao.getMaxPositionInPlaylist(favoritePlaylist.id)
            Log.d(TAG, "收藏列表当前最大位置: $maxPosition")
            
            // 添加歌曲到收藏列表
            val crossRef = PlaylistSongCrossRef(
                playlistId = favoritePlaylist.id,
                songId = songId,
                position = maxPosition + 1
            )
            playlistSongDao.addSongToPlaylist(crossRef)
            Log.d(TAG, "歌曲添加到收藏列表: $songId, 位置: ${maxPosition + 1}")
        } else {
            Log.d(TAG, "歌曲已经在收藏列表中: $songId")
        }
    }
    
    override suspend fun removeFromFavorites(songId: String) {
        Log.d(TAG, "从收藏中移除歌曲: $songId")
        
        // 获取收藏播放列表
        val favoritePlaylist = playlistDao.getFavoritePlaylist()
        if (favoritePlaylist != null) {
            // 从收藏列表中移除歌曲
            playlistSongDao.removeSongFromPlaylist(favoritePlaylist.id, songId)
            Log.d(TAG, "歌曲从收藏列表中移除: $songId")
        } else {
            Log.d(TAG, "收藏列表不存在")
        }
    }
    
    override suspend fun isSongFavorite(songId: String): Boolean {
        // 获取收藏播放列表
        val favoritePlaylist = playlistDao.getFavoritePlaylist()
        if (favoritePlaylist == null) {
            Log.d(TAG, "检查歌曲 $songId 是否收藏: 收藏列表不存在，返回false")
            return false
        }
        
        // 检查歌曲是否在收藏列表中
        val isFavorite = playlistSongDao.isSongInPlaylist(favoritePlaylist.id, songId)
        Log.d(TAG, "检查歌曲 $songId 是否收藏: $isFavorite")
        return isFavorite
    }
    
    override suspend fun toggleFavorite(songId: String): Boolean {
        Log.d(TAG, "切换歌曲收藏状态: $songId")
        
        // 检查当前收藏状态
        val isFavorite = isSongFavorite(songId)
        Log.d(TAG, "当前收藏状态: $isFavorite")
        
        // 切换收藏状态
        if (isFavorite) {
            removeFromFavorites(songId)
            Log.d(TAG, "取消收藏歌曲: $songId")
            return false
        } else {
            addToFavorites(songId)
            Log.d(TAG, "收藏歌曲: $songId")
            return true
        }
    }
    
    override fun getFavoriteSongs(): Flow<List<Song>> {
        Log.d(TAG, "获取收藏歌曲列表")
        
        // 使用flow构建器，在IO线程上安全地执行数据库操作
        return flow {
            // 在IO线程上获取收藏播放列表
            val favoritePlaylist = withContext(Dispatchers.IO) {
                playlistDao.getFavoritePlaylistSync()
            }
            
            if (favoritePlaylist == null) {
                Log.d(TAG, "收藏播放列表不存在，返回空列表")
                emit(emptyList())
                return@flow
            }
            
            Log.d(TAG, "找到收藏播放列表ID: ${favoritePlaylist.id}, 名称: ${favoritePlaylist.name}")
            
            // 创建对数据库查询的Flow
            val songsFlow = playlistSongDao.getSongsInPlaylistFlow(favoritePlaylist.id)
            
            // 收集并转发结果
            songsFlow.collect { songEntities ->
                Log.d(TAG, "收藏列表包含 ${songEntities.size} 首歌曲")
                val domainSongs = songEntities.map { 
                    val song = it.toDomainModel()
                    Log.d(TAG, "收藏歌曲: ID=${song.id}, 标题=${song.title}")
                    song
                }
                emit(domainSongs)
            }
        }.flowOn(Dispatchers.IO) // 确保上游操作在IO线程上执行
    }
    
    /**
     * 保存本地扫描到的歌曲
     */
    suspend fun saveLocalSongs(songs: List<Song>) {
        Log.d(TAG, "保存 ${songs.size} 首本地歌曲")
        
        // 先删除旧的本地歌曲
        songDao.deleteAllLocalSongs()
        
        // 保存新的本地歌曲
        val songEntities = songs.map { SongEntity.fromDomainModel(it, true) }
        songDao.insertSongs(songEntities)
        
        // 创建或更新本地音乐播放列表
        var localPlaylist = playlistDao.getLocalPlaylist()
        if (localPlaylist == null) {
            localPlaylist = PlaylistEntity.createLocalPlaylist()
            playlistDao.insertPlaylist(localPlaylist)
        }
        
        // 更新本地音乐播放列表与歌曲的关系
        playlistSongDao.clearPlaylist(localPlaylist.id)
        
        val crossRefs = songs.mapIndexed { index, song ->
            PlaylistSongCrossRef(
                playlistId = localPlaylist.id,
                songId = song.id,
                position = index
            )
        }
        playlistSongDao.addSongsToPlaylist(crossRefs)
        
        // 如果没有当前播放列表，则创建默认的本地播放列表
        val currentPlaylist = currentPlaylistDao.getCurrentPlaylist()
        if (currentPlaylist == null && songs.isNotEmpty()) {
            val newCurrentPlaylist = CurrentPlaylistEntity.createLocalPlaylist()
            currentPlaylistDao.insertCurrentPlaylist(newCurrentPlaylist)
        }
    }
    
    /**
     * 获取本地歌曲
     */
    suspend fun getLocalSongs(): List<Song> {
        val songEntities = songDao.getLocalSongs()
        return songEntities.map { it.toDomainModel() }
    }
    
    /**
     * 获取本地歌曲数量
     */
    suspend fun countLocalSongs(): Int {
        return songDao.countLocalSongs()
    }
    
    /**
     * 保存当前播放列表
     */
    suspend fun saveCurrentPlaylist(sourceType: String, sourceId: String, currentSongId: String?) {
        val currentPlaylist = CurrentPlaylistEntity(
            sourceType = sourceType,
            sourceId = sourceId,
            currentSongId = currentSongId
        )
        currentPlaylistDao.insertCurrentPlaylist(currentPlaylist)
    }
    
    /**
     * 获取当前播放列表信息
     */
    suspend fun getCurrentPlaylist(): CurrentPlaylistEntity? {
        return currentPlaylistDao.getCurrentPlaylist()
    }
    
    /**
     * 更新当前播放歌曲
     */
    suspend fun updateCurrentSong(songId: String) {
        currentPlaylistDao.updateCurrentSongId(songId)
    }
    
    /**
     * 添加歌曲到播放历史
     * @param songId 歌曲ID
     */
    suspend fun addToHistory(songId: String) {
        val currentTime = System.currentTimeMillis()
        val currentCount = playHistoryDao.getPlayCount(songId) ?: 0
        
        val history = PlayHistoryEntity(
            songId = songId,
            playedAt = currentTime,
            playCount = currentCount + 1
        )
        
        playHistoryDao.insertHistory(history)
        
        // 删除30天前的历史记录
        val thirtyDaysAgo = currentTime - (30 * 24 * 60 * 60 * 1000)
        playHistoryDao.deleteOldHistory(thirtyDaysAgo)
    }
    
    /**
     * 获取最近的播放历史
     * @param limit 返回的记录数量限制
     * @return 按播放时间倒序排列的歌曲列表
     */
    suspend fun getRecentHistory(limit: Int = 50): List<Song> {
        val historyEntities = playHistoryDao.getRecentHistory(limit)
        return historyEntities.mapNotNull { entity ->
            songDao.getSongById(entity.songId)?.toDomainModel()
        }
    }
    
    /**
     * 清除播放历史
     */
    suspend fun clearHistory() {
        playHistoryDao.deleteOldHistory(Long.MAX_VALUE)
    }
} 